package com.macrosolution.exdebito

import java.text.BreakDictionary;
import java.util.Date;

import com.sun.org.apache.bcel.internal.generic.RETURN;

class User implements Serializable{

	transient springSecurityService

	String username
	String password
	String originalPassword
	String name
	String surname
	String cf
	String piva
	String phone
	String mobile
	String personal_email
	String company_email
	Date born
	Provincia bornProvince
	Comune bornMunicipality
	String bornCap
	Address fiscalAddress
	List subjects
	Integer age
	Date	dateCreated
	Date	lastUpdated
	User owner
	boolean enabled = true
	boolean accountExpired
	boolean accountLocked
	boolean passwordExpired
	
	static transients = ['springSecurityService']

	static hasMany = [subjects:User]
	static constraints = {
		username blank: false, unique: true
		password blank: false
		name nullable:true
		surname nullable:true
		cf nullable:true
		piva nullable:true
		phone nullable:true
		mobile nullable:true
		personal_email nullable:true
		company_email nullable:true
		born nullable:true
		bornProvince nullable:true
		bornMunicipality nullable:true
		bornCap nullable:true
		age nullable:true
		owner nullable:true
		fiscalAddress nullable:true
		originalPassword nullable:true
	}

	static mapping = {
		password column: '`password`'
	}
	
	

	@Override
	public String toString() {
		
		return ((surname!=null)?surname:username) +' '+((name!=null)?name:'');
		
	}

	Set<Role> getAuthorities() {
		UserRole.findAllByUser(this).collect { it.role }
	}

	def beforeInsert() {
		encodePassword()
		originalPassword=password
	}

	def beforeUpdate() {
		if (isDirty('password')) {
			if(!password.equals(originalPassword)){
				encodePassword()
			}
		}
	}
	public void addSubject(User user){
		if(!subjects){
			subjects= new ArrayList<User>()
		}
		subjects.add(user);
	}
	
	public List<User> getSubjectsByRole(Role role){
		List<User> users= new ArrayList<User>()
		this.getAuthorities().each{Role rol->
					if(rol.id.equals( role.id)){
						users.add(this);
					}
				}
		if(this.subjects){
			users.addAll(RecSubjectsByRole(this.subjects,role))
		}
		return users
	}
	public List RecSubjectsByRole(List<User> users,Role role){
		List<User> result= new ArrayList<User>()
		if(users){
			users.each {User user->
				user.getAuthorities().each{Role rol->
					if(rol.id.equals( role.id)){
						result.add(user);
					}
				}
				
				if(user.subjects){
					result.addAll(RecSubjectsByRole(user.subjects,role))
				}
			}
		}
		return result
	}
	
	public boolean checkAddRole(Role role){
		List<User> users= new ArrayList<User>()
		boolean result=false;
		Set<Role> roles=this.getAuthorities()
		roles.each {Role r->
			if(r.priority==(role.priority-1)){
				result =true;
			}
		}
		if(result){
			return true;
		}
		if(this.subjects){
			users.addAll(RecCheckAddRole(this.subjects,role))
		}
		if(users && !users.empty){
			result=true;
		}
		return result 
	}
	public List RecCheckAddRole(List<User> users,Role role){
		List<User> result= new ArrayList<User>()
		if(users){
			users.each {User user->
				Set<Role> roles=user.getAuthorities()
				roles.each {Role r->
					if(r.priority==(role.priority-1)){
						result.add(user);
						return result;
					}
				}
				if(user.subjects){
					result.addAll(RecCheckAddRole(user.subjects,role))
				}
			}
		}
		return result
	}
	
	
	public User getParent(User user){
		User result = recGetParent(this,this.subjects,user); 
		return result  
	}
	private User recGetParent(User parent,List subs,User user){
		User  result
		if(subs){
			for(User u:subs){
			if(user.id.equals(u.id)){
				 result =parent;
				return result		
			}
			result = recGetParent(u,u.subjects,user);
			if(result!=null){
				return result
			}
		}
	}
	return result	
	}
	public boolean isReadOnly(){
		boolean result=false;
		Set<Role> roles=getAuthorities()
		if(roles){
			for(Role role:roles){
				if(role.isReadOnly){
					result=true;
					break;
				}
			}
		}
		return result
	}
	
	public boolean hasParentPrivilege(){
		boolean result=false;
		Set<Role> roles=getAuthorities()
		if(roles){
			for(Role role:roles){
				if(role.hasParentPrivilege){
					result=true;
					break;
				}
			}
		}
		return result
	}
	
	public List<User> getFamily(){
		List<User> users= new ArrayList<User>()
		
		if(this.hasParentPrivilege()){
			User parent
			if(this.owner){
				parent=this.owner
			}else{
				parent=getParent(this)
			}
			
			users.addAll(RecFamily(parent.subjects))
		}else{ 
			users.add(this)
			if(this.subjects){
			users.addAll(RecFamily(this.subjects))
			}
		}
		return users
	}
	
	public List RecFamily(List<User> users){
		List<User> result= new ArrayList<User>()
		if(users){
			users.each {User user->
						result.add(user);
						if(user.subjects){
							result.addAll(RecFamily(user.subjects))
						}
			}
		}
		return result
	}
	
	public User getParentRole(String role){
		User user
		if(this.owner){
			user= parentRole(this.owner, role);
		}
		return user
	}
	
	private User parentRole(User parent,String role){
		for(Role auth:parent.getAuthorities()){
			if(auth.authority.equals(role)){
				return parent
			}
		}
		if(parent.owner){
			return parentRole(parent.owner, role)
		}
	}
	
	protected void encodePassword() {
		password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
	}
}
